package upload

import (
	"context"
	"fmt"
	"image"
	_ "image/gif" // 支持 GIF 格式
	"image/jpeg"
	_ "image/jpeg" // 支持 JPEG 格式
	_ "image/png"  // 支持 PNG 格式
	"os"
	"path/filepath"

	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/marcellowy/go-common/gogf/vconfig"
	"github.com/marcellowy/go-common/gogf/vlog"
	"github.com/marcellowy/go-common/tools"
	"github.com/nfnt/resize"

	"mini-upload/api/upload/v1"
)

func (c *ControllerV1) Scaling(ctx context.Context, req *v1.ScalingReq) (res *v1.ScalingRes, err error) {

	if req.Width <= 0 || req.Path == "" {
		err = gerror.NewCode(gcode.CodeInvalidParameter)
		return
	}
	savePath := vconfig.Get("upload.savePath").String()
	req.Path = filepath.Join(savePath, req.Path)
	cacheDir := vconfig.Get("upload.cache", "").String()
	if cacheDir == "" {
		cacheDir = os.TempDir()
	}
	cacheDir = filepath.Join(cacheDir, "scaling")
	if err = os.MkdirAll(cacheDir, os.ModePerm); err != nil {
		vlog.Error(ctx, err, cacheDir)
		err = gerror.NewCode(gcode.CodeInternalError)
		return
	}
	cacheFilename := tools.Md5(req.Path) + fmt.Sprintf("_%d_%d.jpg", req.Width, 0)
	cacheFilename = filepath.Join(cacheDir, cacheFilename)
	if _, err = os.Stat(cacheFilename); err == nil {
		// 文件已经生成,直接使用就好
		g.RequestFromCtx(ctx).Response.ServeFile(cacheFilename)
		return
	}
	file, err := os.Open(req.Path)
	if err != nil {
		vlog.Error(ctx, err)
		err = gerror.NewCode(gcode.CodeInternalError)
		return
	}
	defer file.Close()
	img, _, err := image.Decode(file)
	if err != nil {
		vlog.Error(ctx, err, req.Path)
		err = gerror.NewCode(gcode.CodeInternalError)
		return
	}
	resizedImg := resize.Resize(uint(req.Width), 0, img, resize.Lanczos3)
	var cache *os.File
	if cache, err = os.Create(cacheFilename); err != nil {
		vlog.Error(ctx, err, req.Path)
		err = gerror.NewCode(gcode.CodeInternalError)
		return
	}
	defer cache.Close()
	if err = jpeg.Encode(cache, resizedImg, nil); err != nil {
		vlog.Error(ctx, err, req.Path, cacheFilename)
		err = gerror.NewCode(gcode.CodeInternalError)
		return
	}
	cache.Close()
	g.RequestFromCtx(ctx).Response.ServeFile(cacheFilename)
	return
}
